Getting started
- Install R
Visit https://cran.rstudio.com/ to install R. Follow the instructions for your operating system.
- Install RStudio
Visit https://www.rstudio.com/ to install RStudio. RStudio is an IDE for R that we’ll be working with.
- Open RStudio
You’ll see four panes. The top left is the editor. The bottom left is the console. The top right is the environment. The bottom right contains miscellaneous features, but primarily it’s where plotting output will appear. Of the four, the one that’s new to R relative to Stata is the environment - in Stata language, this the list of all macros you’ve created.
You’ll now be able to open spatialdatanotes.Rmd in RStudio. If you open that, you’ll be able to both read through these notes and easily test out the code. It’s best to follow along with that going forward.
- “Hello world!”
Let’s start with some basics. Try running the following code in the console:
"Hello world!"
[1] "Hello world!"
print("Hello world!")
[1] "Hello world!"
x <- 2 + 2
print(x)
[1] 4
- Data structures
In programming languages, “data structures” are used to store sets that are more complicated than singletons. There are three main types of data structures we’ll run into in R - vectors, matrices, and lists.
Vectors are single dimensional and contain a single type of data. Typical classes of vectors include “integer” (integers), “numeric” (floats/numbers), and “character” (strings). R has another class called “factor”, which is hard to work with, and we won’t talk much about. Vectors can be consructed using the function “c”, which is short for “concatenate”.
x <- c(1, 2, 5)
print(x)
[1] 1 2 5
# get the third element
print(x[3])
[1] 5
# change an element
x[2] <- 4
print(x)
[1] 1 4 5
# operation applied to each element
print(x + 1)
[1] 2 5 6
# vectors addition works as expected
print(x + c(-1, 2, 3))
[1] 0 6 8
# class is a function that returns the class of objects
print(class(x))
[1] "numeric"
Matrices work like two dimensional vectors, for today we’ll only need to know how to create them and print them.
x <- c(0, 0, 2, 0, 1, 1)
print(matrix(x, ncol = 2))
[,1] [,2]
[1,] 0 0
[2,] 0 1
[3,] 2 1
print(matrix(x, ncol = 2, byrow = T))
[,1] [,2]
[1,] 0 0
[2,] 2 0
[3,] 1 1
Lists are similar to vectors, but each element can have an arbitrary data type (and can even be a list!). For example, consider the below example.
x <- list(1, c(2, 3), list(4, c(5, 6)))
print(x)
[[1]]
[1] 1
[[2]]
[1] 2 3
[[3]]
[[3]][[1]]
[1] 4
[[3]][[2]]
[1] 5 6
x is a 3 element list. The first element is just “1” - a numeric vector of length 1. The second element is “c(2, 3)” - a numeric vector of length 2. The third element is “list(4, c(5, 6))” - a 2 element list, the first element of which is “4”, and the second element of which is “c(5, 6)”. Accessing elements of a list is slightly different from vectors
# get a sublist
print(x[1])
[[1]]
[1] 1
print(x[c(1, 3)])
[[1]]
[1] 1
[[2]]
[[2]][[1]]
[1] 4
[[2]][[2]]
[1] 5 6
# get an element of a list
print(x[[1]])
[1] 1
With vectors, there’s no distinction between an element and a length one subvector. With lists, because these two things are different, you can use “[ ]” to get a sublist, and “[[ ]]” to get an element.
- Data frames
A lot of what we’ll want to do using R is working with data. In contrast to Stata, the data we work with in R is stored in the environment just like any other variables. The objects used to store data are called “data frames”. As in Stata, “data frames” are encoded as a list of columns. Each column is either a vector or a list. The length of each column is the same - the number of rows in the data frame. To give an example, a column containing average incomes would be a numeric vector, while a column containing polygons for each row would be a list. Let’s see how to replicate some basic Stata operations.
# data.frame is used to construct a data frame
# row.names is a special argument for the row names
df <- data.frame(row.names = c("a", "b"), x = c(1, 2), y = c("f", "g"))
print(df)
# gen (two identical approaches)
df[,"z"] <- df[,"x"] + 1
print(df)
df$z <- df$x + 1
print(df)
# keep
df2 <- subset(df, z == 3)
print(df2)
# append
df3 <- rbind(df, data.frame(row.names = "c", x = 3, y = "h", z = 4))
print(df3)
- Installing libraries
Libraries in R are the equivalent of packages in Stata. Installing libraries in R is typically straightforward. Two notable exceptions are two libraries we’ll be using today - rgdal (used for reading shapefiles) and rgeos (used for manipulating shapefiles). The first thing to try is the easy approach, but this may not work.
# install.packages(c("sp", "rgdal", "rgeos", "tidyverse"))
You’ll probably get an error. If you’re on Mac, try http://www.janosgyerik.com/installing-rgdal-in-r-on-os-x-mavericks/ these instructions first. If those don’t work, try https://beanumber.github.io/sds192/rgdal-install.html. If you’re on Windows, and this didn’t work, install Linux. If you’re on Linux, run “sudo apt-get update” then “sudo apt-get install libgdal-dev libproj-dev” in the console; after that, it should work.
Some simple examples
Let’s work through an example where we create an SPDF.
- We need to create a Polygon object. We’ll use the Polygon constructor, which takes as an argument a matrix of coordinates.
- We’ll need to create a Polygons object. We’ll use the Polygons constructor, which takes as arguments 1) a list of Polygon objects, and 2) an ID for the Polygons object.
- We’ll create a SpatialPolygons object. We’ll use the SpatialPolygons constructor, which takes as arguments 1) a list of Polygons objects, and 2) a CRS. The latter argument is optional - we’ll use it when we’re working with real spatial data, but when creating some fake spatial data, this doesn’t matter.
- We’ll create a SpatialPolygonsDataFrame object. We can create this in two ways.
- We can use the SpatialPolygonsDataFrame constructor, which takes as arguments 1) a SpatialPolygons object, and 2) a data frame, where the IDs of the SpatialPolygons object must be the same as the row names of the data frame (since a row of a data frame corresponds to an element of the SpatialPolygons object).
- We can use the same notation we used to create a new column of a data frame to create a new column in the SpatialPolygons object.
To do all this, we’ll also first need to load in the library sp, which contains these constructor functions, and tidyverse, which contains some useful miscellaneous R libraries (which includes “alpha”, a function that lets us create transparent colors for use in “plot”).
library(sp)
library(tidyverse)
p1 <- Polygon(matrix(c(0,0,0,1,1,1,1,0), ncol = 2, byrow = T))
p2 <- Polygon(matrix(c(2,0,3,0,2.5,1), ncol = 2, byrow = T))
q1 <- Polygon(matrix(c(0.5,0.5,2.25,0.5,2.25,1.5,0.5,1.5), ncol = 2, byrow = T))
p1 <- Polygons(list(p1), "p1")
p2 <- Polygons(list(p2), "p2")
q1 <- Polygons(list(q1), "q1")
p <- SpatialPolygons(list(p1, p2))
q <- SpatialPolygons(list(q1))
# the below line is the same as "p$shape <- c("Square", "Triangle")"
p <- SpatialPolygonsDataFrame(p, data.frame(row.names = c("p1", "p2"), shape = c("Rectangle", "Triangle")))
# the below line is the same as "q$shape <- "Rectangle""
q <- SpatialPolygonsDataFrame(q, data.frame(row.names = c("q1"), shape = c("Rectangle")))
pq <- rbind(p, q)
print(pq@data)
# pq@data[,"shape"] is just c("Rectangle", "Triangle", "Rectangle")
# plotcols will just be c(1, 2, 1); this is how "match" works
plotcols <- match(pq@data[,"shape"], c("Rectangle", "Triangle"))
plot(pq, col = alpha(plotcols, 0.5), axes = T)

LS0tCnRpdGxlOiAiU3BhdGlhbCBkYXRhIGluIFIgKE5vdGVzKSwgUGFydCAyIgphdXRob3I6IEpvaG4gTG9lc2VyCmRhdGU6IEp1bmUgMTIsIDIwMTcKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgR2V0dGluZyBzdGFydGVkCgoxLiBJbnN0YWxsIFIKClZpc2l0IFtodHRwczovL2NyYW4ucnN0dWRpby5jb20vXShodHRwczovL2NyYW4ucnN0dWRpby5jb20vKSB0byBpbnN0YWxsIFIuIEZvbGxvdyB0aGUgaW5zdHJ1Y3Rpb25zIGZvciB5b3VyIG9wZXJhdGluZyBzeXN0ZW0uCgoyLiBJbnN0YWxsIFJTdHVkaW8KClZpc2l0IFtodHRwczovL3d3dy5yc3R1ZGlvLmNvbS9dKGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tLykgdG8gaW5zdGFsbCBSU3R1ZGlvLiBSU3R1ZGlvIGlzIGFuIElERSBmb3IgUiB0aGF0IHdlJ2xsIGJlIHdvcmtpbmcgd2l0aC4KCjMuIE9wZW4gUlN0dWRpbwoKWW91J2xsIHNlZSBmb3VyIHBhbmVzLiBUaGUgdG9wIGxlZnQgaXMgdGhlIGVkaXRvci4gVGhlIGJvdHRvbSBsZWZ0IGlzIHRoZSBjb25zb2xlLiBUaGUgdG9wIHJpZ2h0IGlzIHRoZSBlbnZpcm9ubWVudC4gVGhlIGJvdHRvbSByaWdodCBjb250YWlucyBtaXNjZWxsYW5lb3VzIGZlYXR1cmVzLCBidXQgcHJpbWFyaWx5IGl0J3Mgd2hlcmUgcGxvdHRpbmcgb3V0cHV0IHdpbGwgYXBwZWFyLiBPZiB0aGUgZm91ciwgdGhlIG9uZSB0aGF0J3MgbmV3IHRvIFIgcmVsYXRpdmUgdG8gU3RhdGEgaXMgdGhlIGVudmlyb25tZW50IC0gaW4gU3RhdGEgbGFuZ3VhZ2UsIHRoaXMgdGhlIGxpc3Qgb2YgYWxsIG1hY3JvcyB5b3UndmUgY3JlYXRlZC4KCllvdSdsbCBub3cgYmUgYWJsZSB0byBvcGVuIHNwYXRpYWxkYXRhbm90ZXMuUm1kIGluIFJTdHVkaW8uIElmIHlvdSBvcGVuIHRoYXQsIHlvdSdsbCBiZSBhYmxlIHRvIGJvdGggcmVhZCB0aHJvdWdoIHRoZXNlIG5vdGVzIGFuZCBlYXNpbHkgdGVzdCBvdXQgdGhlIGNvZGUuIEl0J3MgYmVzdCB0byBmb2xsb3cgYWxvbmcgd2l0aCB0aGF0IGdvaW5nIGZvcndhcmQuCgo0LiAiSGVsbG8gd29ybGQhIgoKTGV0J3Mgc3RhcnQgd2l0aCBzb21lIGJhc2ljcy4gVHJ5IHJ1bm5pbmcgdGhlIGZvbGxvd2luZyBjb2RlIGluIHRoZSBjb25zb2xlOgoKYGBge3J9CiJIZWxsbyB3b3JsZCEiCnByaW50KCJIZWxsbyB3b3JsZCEiKQp4IDwtIDIgKyAyCnByaW50KHgpCmBgYAoKNS4gRGF0YSBzdHJ1Y3R1cmVzCgpJbiBwcm9ncmFtbWluZyBsYW5ndWFnZXMsICJkYXRhIHN0cnVjdHVyZXMiIGFyZSB1c2VkIHRvIHN0b3JlIHNldHMgdGhhdCBhcmUgbW9yZSBjb21wbGljYXRlZCB0aGFuIHNpbmdsZXRvbnMuIFRoZXJlIGFyZSB0aHJlZSBtYWluIHR5cGVzIG9mIGRhdGEgc3RydWN0dXJlcyB3ZSdsbCBydW4gaW50byBpbiBSIC0gdmVjdG9ycywgbWF0cmljZXMsIGFuZCBsaXN0cy4KClZlY3RvcnMgYXJlIHNpbmdsZSBkaW1lbnNpb25hbCBhbmQgY29udGFpbiBhIHNpbmdsZSB0eXBlIG9mIGRhdGEuIFR5cGljYWwgY2xhc3NlcyBvZiB2ZWN0b3JzIGluY2x1ZGUgImludGVnZXIiIChpbnRlZ2VycyksICJudW1lcmljIiAoZmxvYXRzL251bWJlcnMpLCBhbmQgImNoYXJhY3RlciIgKHN0cmluZ3MpLiBSIGhhcyBhbm90aGVyIGNsYXNzIGNhbGxlZCAiZmFjdG9yIiwgd2hpY2ggaXMgaGFyZCB0byB3b3JrIHdpdGgsIGFuZCB3ZSB3b24ndCB0YWxrIG11Y2ggYWJvdXQuIFZlY3RvcnMgY2FuIGJlIGNvbnNydWN0ZWQgdXNpbmcgdGhlIGZ1bmN0aW9uICJjIiwgd2hpY2ggaXMgc2hvcnQgZm9yICJjb25jYXRlbmF0ZSIuCgpgYGB7cn0KeCA8LSBjKDEsIDIsIDUpCnByaW50KHgpCiMgZ2V0IHRoZSB0aGlyZCBlbGVtZW50CnByaW50KHhbM10pCiMgY2hhbmdlIGFuIGVsZW1lbnQKeFsyXSA8LSA0CnByaW50KHgpCiMgb3BlcmF0aW9uIGFwcGxpZWQgdG8gZWFjaCBlbGVtZW50CnByaW50KHggKyAxKQojIHZlY3RvcnMgYWRkaXRpb24gd29ya3MgYXMgZXhwZWN0ZWQKcHJpbnQoeCArIGMoLTEsIDIsIDMpKQojIGNsYXNzIGlzIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBjbGFzcyBvZiBvYmplY3RzCnByaW50KGNsYXNzKHgpKQpgYGAKCk1hdHJpY2VzIHdvcmsgbGlrZSB0d28gZGltZW5zaW9uYWwgdmVjdG9ycywgZm9yIHRvZGF5IHdlJ2xsIG9ubHkgbmVlZCB0byBrbm93IGhvdyB0byBjcmVhdGUgdGhlbSBhbmQgcHJpbnQgdGhlbS4KCmBgYHtyfQp4IDwtIGMoMCwgMCwgMiwgMCwgMSwgMSkKcHJpbnQobWF0cml4KHgsIG5jb2wgPSAyKSkKcHJpbnQobWF0cml4KHgsIG5jb2wgPSAyLCBieXJvdyA9IFQpKQpgYGAKCkxpc3RzIGFyZSBzaW1pbGFyIHRvIHZlY3RvcnMsIGJ1dCBlYWNoIGVsZW1lbnQgY2FuIGhhdmUgYW4gYXJiaXRyYXJ5IGRhdGEgdHlwZSAoYW5kIGNhbiBldmVuIGJlIGEgbGlzdCEpLiBGb3IgZXhhbXBsZSwgY29uc2lkZXIgdGhlIGJlbG93IGV4YW1wbGUuCgpgYGB7cn0KeCA8LSBsaXN0KDEsIGMoMiwgMyksIGxpc3QoNCwgYyg1LCA2KSkpCnByaW50KHgpCmBgYAoKeCBpcyBhIDMgZWxlbWVudCBsaXN0LiBUaGUgZmlyc3QgZWxlbWVudCBpcyBqdXN0ICIxIiAtIGEgbnVtZXJpYyB2ZWN0b3Igb2YgbGVuZ3RoIDEuIFRoZSBzZWNvbmQgZWxlbWVudCBpcyAiYygyLCAzKSIgLSBhIG51bWVyaWMgdmVjdG9yIG9mIGxlbmd0aCAyLiBUaGUgdGhpcmQgZWxlbWVudCBpcyAibGlzdCg0LCBjKDUsIDYpKSIgLSBhIDIgZWxlbWVudCBsaXN0LCB0aGUgZmlyc3QgZWxlbWVudCBvZiB3aGljaCBpcyAiNCIsIGFuZCB0aGUgc2Vjb25kIGVsZW1lbnQgb2Ygd2hpY2ggaXMgImMoNSwgNikiLiBBY2Nlc3NpbmcgZWxlbWVudHMgb2YgYSBsaXN0IGlzIHNsaWdodGx5IGRpZmZlcmVudCBmcm9tIHZlY3RvcnMKCmBgYHtyfQojIGdldCBhIHN1Ymxpc3QKcHJpbnQoeFsxXSkKcHJpbnQoeFtjKDEsIDMpXSkKIyBnZXQgYW4gZWxlbWVudCBvZiBhIGxpc3QKcHJpbnQoeFtbMV1dKQpgYGAKCldpdGggdmVjdG9ycywgdGhlcmUncyBubyBkaXN0aW5jdGlvbiBiZXR3ZWVuIGFuIGVsZW1lbnQgYW5kIGEgbGVuZ3RoIG9uZSBzdWJ2ZWN0b3IuIFdpdGggbGlzdHMsIGJlY2F1c2UgdGhlc2UgdHdvIHRoaW5ncyBhcmUgZGlmZmVyZW50LCB5b3UgY2FuIHVzZSAiWyBdIiB0byBnZXQgYSBzdWJsaXN0LCBhbmQgIltbIF1dIiB0byBnZXQgYW4gZWxlbWVudC4KCjYuIERhdGEgZnJhbWVzCgpBIGxvdCBvZiB3aGF0IHdlJ2xsIHdhbnQgdG8gZG8gdXNpbmcgUiBpcyB3b3JraW5nIHdpdGggZGF0YS4gSW4gY29udHJhc3QgdG8gU3RhdGEsIHRoZSBkYXRhIHdlIHdvcmsgd2l0aCBpbiBSIGlzIHN0b3JlZCBpbiB0aGUgZW52aXJvbm1lbnQganVzdCBsaWtlIGFueSBvdGhlciB2YXJpYWJsZXMuIFRoZSBvYmplY3RzIHVzZWQgdG8gc3RvcmUgZGF0YSBhcmUgY2FsbGVkICJkYXRhIGZyYW1lcyIuIEFzIGluIFN0YXRhLCAiZGF0YSBmcmFtZXMiIGFyZSBlbmNvZGVkIGFzIGEgbGlzdCBvZiBjb2x1bW5zLiBFYWNoIGNvbHVtbiBpcyBlaXRoZXIgYSB2ZWN0b3Igb3IgYSBsaXN0LiBUaGUgbGVuZ3RoIG9mIGVhY2ggY29sdW1uIGlzIHRoZSBzYW1lIC0gdGhlIG51bWJlciBvZiByb3dzIGluIHRoZSBkYXRhIGZyYW1lLiBUbyBnaXZlIGFuIGV4YW1wbGUsIGEgY29sdW1uIGNvbnRhaW5pbmcgYXZlcmFnZSBpbmNvbWVzIHdvdWxkIGJlIGEgbnVtZXJpYyB2ZWN0b3IsIHdoaWxlIGEgY29sdW1uIGNvbnRhaW5pbmcgcG9seWdvbnMgZm9yIGVhY2ggcm93IHdvdWxkIGJlIGEgbGlzdC4gTGV0J3Mgc2VlIGhvdyB0byByZXBsaWNhdGUgc29tZSBiYXNpYyBTdGF0YSBvcGVyYXRpb25zLgoKYGBge3J9CiMgZGF0YS5mcmFtZSBpcyB1c2VkIHRvIGNvbnN0cnVjdCBhIGRhdGEgZnJhbWUKIyByb3cubmFtZXMgaXMgYSBzcGVjaWFsIGFyZ3VtZW50IGZvciB0aGUgcm93IG5hbWVzCmRmIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzID0gYygiYSIsICJiIiksIHggPSBjKDEsIDIpLCB5ID0gYygiZiIsICJnIikpCnByaW50KGRmKQojIGdlbiAodHdvIGlkZW50aWNhbCBhcHByb2FjaGVzKQpkZlssInoiXSA8LSBkZlssIngiXSArIDEKcHJpbnQoZGYpCmRmJHogPC0gIGRmJHggKyAxCnByaW50KGRmKQojIGtlZXAKZGYyIDwtIHN1YnNldChkZiwgeiA9PSAzKQpwcmludChkZjIpCiMgYXBwZW5kCmRmMyA8LSByYmluZChkZiwgZGF0YS5mcmFtZShyb3cubmFtZXMgPSAiYyIsIHggPSAzLCB5ID0gImgiLCB6ID0gNCkpCnByaW50KGRmMykKYGBgCgo3LiBJbnN0YWxsaW5nIGxpYnJhcmllcwoKTGlicmFyaWVzIGluIFIgYXJlIHRoZSBlcXVpdmFsZW50IG9mIHBhY2thZ2VzIGluIFN0YXRhLiBJbnN0YWxsaW5nIGxpYnJhcmllcyBpbiBSIGlzIHR5cGljYWxseSBzdHJhaWdodGZvcndhcmQuIFR3byBub3RhYmxlIGV4Y2VwdGlvbnMgYXJlIHR3byBsaWJyYXJpZXMgd2UnbGwgYmUgdXNpbmcgdG9kYXkgLSByZ2RhbCAodXNlZCBmb3IgcmVhZGluZyBzaGFwZWZpbGVzKSBhbmQgcmdlb3MgKHVzZWQgZm9yIG1hbmlwdWxhdGluZyBzaGFwZWZpbGVzKS4gVGhlIGZpcnN0IHRoaW5nIHRvIHRyeSBpcyB0aGUgZWFzeSBhcHByb2FjaCwgYnV0IHRoaXMgbWF5IG5vdCB3b3JrLgoKYGBge3IsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIGluc3RhbGwucGFja2FnZXMoYygic3AiLCAicmdkYWwiLCAicmdlb3MiLCAidGlkeXZlcnNlIikpCmBgYAoKWW91J2xsIHByb2JhYmx5IGdldCBhbiBlcnJvci4gSWYgeW91J3JlIG9uIE1hYywgdHJ5IFtodHRwOi8vd3d3Lmphbm9zZ3llcmlrLmNvbS9pbnN0YWxsaW5nLXJnZGFsLWluLXItb24tb3MteC1tYXZlcmlja3MvXShodHRwOi8vd3d3Lmphbm9zZ3llcmlrLmNvbS9pbnN0YWxsaW5nLXJnZGFsLWluLXItb24tb3MteC1tYXZlcmlja3MvKSB0aGVzZSBpbnN0cnVjdGlvbnMgZmlyc3QuIElmIHRob3NlIGRvbid0IHdvcmssIHRyeSBbaHR0cHM6Ly9iZWFudW1iZXIuZ2l0aHViLmlvL3NkczE5Mi9yZ2RhbC1pbnN0YWxsLmh0bWxdKGh0dHBzOi8vYmVhbnVtYmVyLmdpdGh1Yi5pby9zZHMxOTIvcmdkYWwtaW5zdGFsbC5odG1sKS4gSWYgeW91J3JlIG9uIFdpbmRvd3MsIGFuZCB0aGlzIGRpZG4ndCB3b3JrLCBpbnN0YWxsIExpbnV4LiBJZiB5b3UncmUgb24gTGludXgsIHJ1biAic3VkbyBhcHQtZ2V0IHVwZGF0ZSIgdGhlbiAic3VkbyBhcHQtZ2V0IGluc3RhbGwgbGliZ2RhbC1kZXYgbGlicHJvai1kZXYiIGluIHRoZSBjb25zb2xlOyBhZnRlciB0aGF0LCBpdCBzaG91bGQgd29yay4KCiMjIFNoYXBlZmlsZXMKClR5cGljYWxseSwgc3BhdGlhbCBkYXRhIHdpbGwgYmUgc3RvcmVkIGluIEVTUkkgU2hhcGVmaWxlcy4gVGhlc2Ugc2hhcGVmaWxlcyBjb25zaXN0IG9mIGEgc2VyaWVzIG9mIGZpbGVzICh3aGljaCB0b2dldGhlciBhcmUgb2Z0ZW4gcmVmZXJyZWQgdG8gYXMgYSAibGF5ZXIiKSwgbW9zdCBpbXBvcnRhbnRseSBhIC5zaHAgZmlsZSBhbmQgYSAuZGJmIGZpbGUuIFRoZSAuZGJmIGZpbGUgaXMgc2ltaWxhciB0byBhIC5kdGEgLSBpdCBjb250YWlucyBhIGRhdGFiYXNlLCBob3dldmVyIGVhY2ggcm93IGlzIG5vdyBhc3NvY2lhdGVkIHdpdGggYSBwYXJ0aWN1bGFyIHNoYXBlLiBUaGUgLnNocCBmaWxlIGNvbnRhaW5zIHRoZSBnZW9tZXRyaWVzLCB0aGUgZGF0YSB3aGljaCBkZWZpbmVzIGVhY2ggc2hhcGUuCgpgYGB7ciwgZWNobyA9IEZ9CiMgQUREIFRISVMgTElORSBUTyBDSEFOR0UgUkFOSyBESVJFQ1RJT04gOiBncmFwaFtyYW5rZGlyID0gTFJdCkRpYWdyYW1tZVI6OmdyVml6KCIKZGlncmFwaCB7CkFbbGFiZWwgPSAnU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lJ10KQltsYWJlbCA9ICdAcG9seWdvbnNcbmNsYXNzOiBsaXN0J10KQ1tsYWJlbCA9ICdQb2x5Z29ucyddCkRbbGFiZWwgPSAnQFBvbHlnb25zXG5jbGFzczogbGlzdCddCkVbbGFiZWwgPSAnUG9seWdvbiddCkZbbGFiZWwgPSAnQGNvb3Jkc1xuY2xhc3M6IG1hdHJpeCddCkdbbGFiZWwgPSAnQGRhdGFcbmNsYXNzOiBkYXRhLmZyYW1lJ10KSFtsYWJlbCA9ICdAcHJvajRzdHJpbmdcbmNsYXNzOiBDUlMnXQpBLT5CIEEtPkcgQS0+SCBCLT5DIEMtPkQgRC0+RSBFLT5GCn0KIiwgaGVpZ2h0ID0gNDAwKQpgYGAKClIncyBkYXRhIHN0cnVjdHVyZXMgZm9yIHN0b3Jpbmcgc3BhdGlhbCBkYXRhIGZvbGxvd3MgdGhpcyBhcHByb2FjaC4gVGhlIG1vc3QgY29tbW9uIG9iamVjdCB3ZSdsbCBiZSB3b3JraW5nIHdpdGggaXMgYSBTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWUsIHdoaWNoIEknbGwgcmVmZXIgdG8gYXMgYW4gIlNQREYiLiBBbiBTUERGIGhhcyAzIG1haW4gYXR0cmlidXRlcyAobm90ZSB0aGF0IGF0dHJpYnV0ZXMgYXJlIGRpZmZlcmVudCBmcm9tIGVsZW1lbnRzIG9mIGEgbGlzdCBvciBhIHZlY3RvciAtIHRoZXkgYXJlIGFjY2Vzc2VkIHVzaW5nICJcQCIpLiBGaXJzdCwgIlxAcHJvajRzdHJpbmciIHN0b3JlcyB0aGUgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtICgiQ1JTIikgb2YgdGhlIHNoYXBlZmlsZS4gQSBDUlMgZGVmaW5lcyBob3cgY29vcmRpbmF0ZXMgcmVsYXRlIHRvIGxvY2F0aW9ucyAtIGZvciBleGFtcGxlLCAiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiLCB0aGUgbW9zdCBjb21tb24gQ1JTIHlvdSdsbCBzZWUsIGhhcyBjb29yZGluYXRlcyBhcyBsb25naXR1ZGUgYW5kIGxhdGl0dWRlLiBPdGhlciB1c2VmdWwgcHJvamVjdGlvbnMgaW5jbHVkZSBlcXVhbCBhcmVhIHByb2plY3Rpb25zIChzZWUgW2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9dlZYLVByQlJ0VFldKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9dlZYLVByQlJ0VFkpKSBhbmQsIGZvciBhbmFseXNpcyBvZiByZWxhdGl2ZSBzbWFsbCBhcmVhcyB3aGVyZSB0aGUgRWFydGggaXMgYXBwcm94aW1hdGVseSBmbGF0LCBVVE0gKHdoaWNoIGdpdmVzIGNvb3JkaW5hdGVzIGluIG1ldGVycykuIAoKIyMgU29tZSBzaW1wbGUgZXhhbXBsZXMKCkxldCdzIHdvcmsgdGhyb3VnaCBhbiBleGFtcGxlIHdoZXJlIHdlIGNyZWF0ZSBhbiBTUERGLgoKMS4gV2UgbmVlZCB0byBjcmVhdGUgYSBQb2x5Z29uIG9iamVjdC4gV2UnbGwgdXNlIHRoZSBQb2x5Z29uIGNvbnN0cnVjdG9yLCB3aGljaCB0YWtlcyBhcyBhbiBhcmd1bWVudCBhIG1hdHJpeCBvZiBjb29yZGluYXRlcy4KMi4gV2UnbGwgbmVlZCB0byBjcmVhdGUgYSBQb2x5Z29ucyBvYmplY3QuIFdlJ2xsIHVzZSB0aGUgUG9seWdvbnMgY29uc3RydWN0b3IsIHdoaWNoIHRha2VzIGFzIGFyZ3VtZW50cyAxKSBhIGxpc3Qgb2YgUG9seWdvbiBvYmplY3RzLCBhbmQgMikgYW4gSUQgZm9yIHRoZSBQb2x5Z29ucyBvYmplY3QuCjMuIFdlJ2xsIGNyZWF0ZSBhIFNwYXRpYWxQb2x5Z29ucyBvYmplY3QuIFdlJ2xsIHVzZSB0aGUgU3BhdGlhbFBvbHlnb25zIGNvbnN0cnVjdG9yLCB3aGljaCB0YWtlcyBhcyBhcmd1bWVudHMgMSkgYSBsaXN0IG9mIFBvbHlnb25zIG9iamVjdHMsIGFuZCAyKSBhIENSUy4gVGhlIGxhdHRlciBhcmd1bWVudCBpcyBvcHRpb25hbCAtIHdlJ2xsIHVzZSBpdCB3aGVuIHdlJ3JlIHdvcmtpbmcgd2l0aCByZWFsIHNwYXRpYWwgZGF0YSwgYnV0IHdoZW4gY3JlYXRpbmcgc29tZSBmYWtlIHNwYXRpYWwgZGF0YSwgdGhpcyBkb2Vzbid0IG1hdHRlci4KNC4gV2UnbGwgY3JlYXRlIGEgU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIG9iamVjdC4gV2UgY2FuIGNyZWF0ZSB0aGlzIGluIHR3byB3YXlzLgogICAgLSBXZSBjYW4gdXNlIHRoZSBTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWUgY29uc3RydWN0b3IsIHdoaWNoIHRha2VzIGFzIGFyZ3VtZW50cyAxKSBhIFNwYXRpYWxQb2x5Z29ucyBvYmplY3QsIGFuZCAyKSBhIGRhdGEgZnJhbWUsIHdoZXJlIHRoZSBJRHMgb2YgdGhlIFNwYXRpYWxQb2x5Z29ucyBvYmplY3QgbXVzdCBiZSB0aGUgc2FtZSBhcyB0aGUgcm93IG5hbWVzIG9mIHRoZSBkYXRhIGZyYW1lIChzaW5jZSBhIHJvdyBvZiBhIGRhdGEgZnJhbWUgY29ycmVzcG9uZHMgdG8gYW4gZWxlbWVudCBvZiB0aGUgU3BhdGlhbFBvbHlnb25zIG9iamVjdCkuCiAgICAtIFdlIGNhbiB1c2UgdGhlIHNhbWUgbm90YXRpb24gd2UgdXNlZCB0byBjcmVhdGUgYSBuZXcgY29sdW1uIG9mIGEgZGF0YSBmcmFtZSB0byBjcmVhdGUgYSBuZXcgY29sdW1uIGluIHRoZSBTcGF0aWFsUG9seWdvbnMgb2JqZWN0LgogICAgClRvIGRvIGFsbCB0aGlzLCB3ZSdsbCBhbHNvIGZpcnN0IG5lZWQgdG8gbG9hZCBpbiB0aGUgbGlicmFyeSBzcCwgd2hpY2ggY29udGFpbnMgdGhlc2UgY29uc3RydWN0b3IgZnVuY3Rpb25zLCBhbmQgdGlkeXZlcnNlLCB3aGljaCBjb250YWlucyBzb21lIHVzZWZ1bCBtaXNjZWxsYW5lb3VzIFIgbGlicmFyaWVzICh3aGljaCBpbmNsdWRlcyAiYWxwaGEiLCBhIGZ1bmN0aW9uIHRoYXQgbGV0cyB1cyBjcmVhdGUgdHJhbnNwYXJlbnQgY29sb3JzIGZvciB1c2UgaW4gInBsb3QiKS4KCmBgYHtyLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShzcCkKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKYGBge3J9CnAxIDwtIFBvbHlnb24obWF0cml4KGMoMCwwLDAsMSwxLDEsMSwwKSwgbmNvbCA9IDIsIGJ5cm93ID0gVCkpCnAyIDwtIFBvbHlnb24obWF0cml4KGMoMiwwLDMsMCwyLjUsMSksIG5jb2wgPSAyLCBieXJvdyA9IFQpKQpxMSA8LSBQb2x5Z29uKG1hdHJpeChjKDAuNSwwLjUsMi4yNSwwLjUsMi4yNSwxLjUsMC41LDEuNSksIG5jb2wgPSAyLCBieXJvdyA9IFQpKQpwMSA8LSBQb2x5Z29ucyhsaXN0KHAxKSwgInAxIikKcDIgPC0gUG9seWdvbnMobGlzdChwMiksICJwMiIpCnExIDwtIFBvbHlnb25zKGxpc3QocTEpLCAicTEiKQpwIDwtIFNwYXRpYWxQb2x5Z29ucyhsaXN0KHAxLCBwMikpCnEgPC0gU3BhdGlhbFBvbHlnb25zKGxpc3QocTEpKQojIHRoZSBiZWxvdyBsaW5lIGlzIHRoZSBzYW1lIGFzICJwJHNoYXBlIDwtIGMoIlNxdWFyZSIsICJUcmlhbmdsZSIpIgpwIDwtIFNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZShwLCBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGMoInAxIiwgInAyIiksIHNoYXBlID0gYygiUmVjdGFuZ2xlIiwgIlRyaWFuZ2xlIikpKQojIHRoZSBiZWxvdyBsaW5lIGlzIHRoZSBzYW1lIGFzICJxJHNoYXBlIDwtICJSZWN0YW5nbGUiIgpxIDwtIFNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZShxLCBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGMoInExIiksIHNoYXBlID0gYygiUmVjdGFuZ2xlIikpKQpwcSA8LSByYmluZChwLCBxKQpwcmludChwcUBkYXRhKQojIHBxQGRhdGFbLCJzaGFwZSJdIGlzIGp1c3QgYygiUmVjdGFuZ2xlIiwgIlRyaWFuZ2xlIiwgIlJlY3RhbmdsZSIpCiMgcGxvdGNvbHMgd2lsbCBqdXN0IGJlIGMoMSwgMiwgMSk7IHRoaXMgaXMgaG93ICJtYXRjaCIgd29ya3MKcGxvdGNvbHMgPC0gbWF0Y2gocHFAZGF0YVssInNoYXBlIl0sIGMoIlJlY3RhbmdsZSIsICJUcmlhbmdsZSIpKQpwbG90KHBxLCBjb2wgPSBhbHBoYShwbG90Y29scywgMC41KSwgYXhlcyA9IFQpCmBgYAo=